/**
 * @file      HMC5883L.h
 * @brief     HMC5883L三轴磁力计传感器驱动
 * @version   1.0
 * @date      2025-01-22
 */

#ifndef HMC5883L_H
#define HMC5883L_H

#include <stdint.h>
#include <stdbool.h>
#include "ti_msp_dl_config.h"

/*************************************************************************************************/
/* 宏定义 */
/*************************************************************************************************/

/* I2C方向定义 - 用于兼容MSPM0 DriverLib */
#ifndef DL_I2C_CONTROLLER_DIRECTION_TX
#define DL_I2C_CONTROLLER_DIRECTION_TX 0
#endif

#ifndef DL_I2C_CONTROLLER_DIRECTION_RX
#define DL_I2C_CONTROLLER_DIRECTION_RX 1
#endif

/* I2C地址 */
#define HMC5883L_I2C_ADDR              0x1E  // HMC5883L的7位I2C地址
                                             // 8-bit write address: 0x3C (0x1E << 1)
                                             // 8-bit read address:  0x3D ((0x1E << 1) | 1)

/* 寄存器地址 */
#define HMC5883L_REG_CONFIG_A          0x00  // 配置寄存器A
#define HMC5883L_REG_CONFIG_B          0x01  // 配置寄存器B
#define HMC5883L_REG_MODE              0x02  // 模式寄存器
#define HMC5883L_REG_DATA_X_MSB        0x03  // X轴数据高字节寄存器
#define HMC5883L_REG_DATA_X_LSB        0x04  // X轴数据低字节寄存器
#define HMC5883L_REG_DATA_Z_MSB        0x05  // Z轴数据高字节寄存器
#define HMC5883L_REG_DATA_Z_LSB        0x06  // Z轴数据低字节寄存器
#define HMC5883L_REG_DATA_Y_MSB        0x07  // Y轴数据高字节寄存器
#define HMC5883L_REG_DATA_Y_LSB        0x08  // Y轴数据低字节寄存器
#define HMC5883L_REG_STATUS            0x09  // 状态寄存器
#define HMC5883L_REG_ID_A              0x0A  // 识别寄存器A
#define HMC5883L_REG_ID_B              0x0B  // 识别寄存器B
#define HMC5883L_REG_ID_C              0x0C  // 识别寄存器C

/* 配置寄存器A位定义 */
#define HMC5883L_SAMPLES_1             0x00  // 每次测量的样本数: 1
#define HMC5883L_SAMPLES_2             0x20  // 每次测量的样本数: 2
#define HMC5883L_SAMPLES_4             0x40  // 每次测量的样本数: 4
#define HMC5883L_SAMPLES_8             0x60  // 每次测量的样本数: 8
#define HMC5883L_DATARATE_0_75         0x00  // 输出速率: 0.75 Hz
#define HMC5883L_DATARATE_1_5          0x04  // 输出速率: 1.5 Hz
#define HMC5883L_DATARATE_3            0x08  // 输出速率: 3 Hz
#define HMC5883L_DATARATE_7_5          0x0C  // 输出速率: 7.5 Hz
#define HMC5883L_DATARATE_15           0x10  // 输出速率: 15 Hz
#define HMC5883L_DATARATE_30           0x14  // 输出速率: 30 Hz
#define HMC5883L_DATARATE_75           0x18  // 输出速率: 75 Hz
#define HMC5883L_NORMAL_MODE           0x00  // 正常测量配置
#define HMC5883L_POS_BIAS              0x01  // 正偏置配置
#define HMC5883L_NEG_BIAS              0x02  // 负偏置配置

/* 配置寄存器B位定义 - 增益设置 */
#define HMC5883L_GAIN_1370             0x00  // ±0.88 Ga, 1370 LSB/Gauss
#define HMC5883L_GAIN_1090             0x20  // ±1.3 Ga, 1090 LSB/Gauss
#define HMC5883L_GAIN_820              0x40  // ±1.9 Ga, 820 LSB/Gauss
#define HMC5883L_GAIN_660              0x60  // ±2.5 Ga, 660 LSB/Gauss
#define HMC5883L_GAIN_440              0x80  // ±4.0 Ga, 440 LSB/Gauss
#define HMC5883L_GAIN_390              0xA0  // ±4.7 Ga, 390 LSB/Gauss
#define HMC5883L_GAIN_330              0xC0  // ±5.6 Ga, 330 LSB/Gauss
#define HMC5883L_GAIN_230              0xE0  // ±8.1 Ga, 230 LSB/Gauss

/* 模式寄存器位定义 */
#define HMC5883L_MODE_CONTINUOUS       0x00  // 连续测量模式
#define HMC5883L_MODE_SINGLE           0x01  // 单次测量模式
#define HMC5883L_MODE_IDLE             0x02  // 空闲模式
#define HMC5883L_MODE_IDLE_2           0x03  // 空闲模式

/* 状态定义 */
#define HMC5883L_OK                    0     // 操作成功
#define HMC5883L_ERROR                 1     // 操作失败

// 默认EMA滤波器alpha值 (0 < alpha < 1), 值越小越平滑
#define HMC5883L_DEFAULT_FILTER_ALPHA  0.1f

/*************************************************************************************************/
/* 数据结构定义 */
/*************************************************************************************************/

/**
 * @brief HMC5883L校准数据结构体
 */
typedef struct {
    int16_t x_offset;      // X轴硬铁偏移
    int16_t y_offset;      // Y轴硬铁偏移
    int16_t z_offset;      // Z轴硬铁偏移
    float   x_scale;       // X轴软铁缩放
    float   y_scale;       // Y轴软铁缩放
    float   z_scale;       // Z轴软铁缩放
    bool    initialized;   // 是否已校准
} HMC5883L_CalibrationData_t;


/**
 * @brief HMC5883L数据结构体
 */
typedef struct {
    int16_t x;             // X轴原始数据
    int16_t y;             // Y轴原始数据
    int16_t z;             // Z轴原始数据
    float mag_x;           // X轴磁场强度(Gauss)
    float mag_y;           // Y轴磁场强度(Gauss)
    float mag_z;           // Z轴磁场强度(Gauss)
    float heading;         // 磁航向角(度,0-360)
    uint32_t timestamp;    // 时间戳(ms)
} HMC5883L_Data_t;

/**
 * @brief HMC5883L配置结构体
 */
typedef struct {
    uint8_t samples;        // 每次测量样本数
    uint8_t dataRate;       // 数据输出速率
    uint8_t gain;           // 增益设置
    uint8_t measureMode;    // 测量模式
    bool highSpeed;         // 高速I2C模式(400kHz)
    float declination;      // 磁偏角(度)
    float scale;            // 比例因子(根据增益设置)
} HMC5883L_Config_t;

/*************************************************************************************************/
/* 函数声明 */
/*************************************************************************************************/

/**
 * @brief 初始化HMC5883L传感器
 * @return HMC5883L_OK: 初始化成功, HMC5883L_ERROR: 初始化失败
 */
uint8_t HMC5883L_Init(void);

/**
 * @brief 设置HMC5883L配置
 * @param config 配置结构体指针
 * @return HMC5883L_OK: 设置成功, HMC5883L_ERROR: 设置失败
 */
uint8_t HMC5883L_SetConfig(const HMC5883L_Config_t *config);

/**
 * @brief 获取HMC5883L当前配置
 * @param config 配置结构体指针(用于存储获取的配置)
 * @return HMC5883L_OK: 获取成功, HMC5883L_ERROR: 获取失败
 */
uint8_t HMC5883L_GetConfig(HMC5883L_Config_t *config);

/**
 * @brief 读取HMC5883L磁场数据
 * @param data 数据结构体指针(用于存储读取的数据)
 * @return HMC5883L_OK: 读取成功, HMC5883L_ERROR: 读取失败
 */
uint8_t HMC5883L_ReadMag(HMC5883L_Data_t *data);

/**
 * @brief 读取HMC5883L磁场数据并进行滤波
 * @param data 数据结构体指针(用于存储滤波后的数据)
 * @return HMC5883L_OK: 读取成功, HMC5883L_ERROR: 读取失败
 */
uint8_t HMC5883L_ReadMagFiltered(HMC5883L_Data_t *data);

/**
 * @brief 设置滤波器的平滑因子 (alpha)
 * @param alpha 平滑因子 (0.0 to 1.0)
 */
void HMC5883L_SetFilterAlpha(float alpha);

/**
 * @brief 启动HMC5883L硬铁和软铁校准过程
 * @note  调用此函数后，需要在各个方向上缓慢旋转传感器以采集数据
 */
void HMC5883L_Calibration_Start(void);

/**
 * @brief 停止HMC5883L校准过程并计算校准参数
 */
void HMC5883L_Calibration_Stop(void);

/**
 * @brief 检查校准过程是否正在运行
 * @return true: 正在校准, false: 未在校准
 */
bool HMC5883L_Calibration_IsRunning(void);

/**
 * @brief 加载校准数据
 * @param cal_data 指向包含校准数据的结构体
 */
void HMC5883L_Calibration_Load(const HMC5883L_CalibrationData_t *cal_data);

/**
 * @brief 获取当前校准数据
 * @param cal_data 指向用于存储校准数据的结构体
 */
void HMC5883L_Calibration_Get(HMC5883L_CalibrationData_t *cal_data);

/**
 * @brief 执行HMC5883L自测
 * @return HMC5883L_OK: 自测通过, HMC5883L_ERROR: 自测失败
 */
uint8_t HMC5883L_SelfTest(void);

/**
 * @brief 设置HMC5883L测量模式
 * @param mode 测量模式(HMC5883L_MODE_CONTINUOUS, HMC5883L_MODE_SINGLE, HMC5883L_MODE_IDLE)
 * @return HMC5883L_OK: 设置成功, HMC5883L_ERROR: 设置失败
 */
uint8_t HMC5883L_SetMode(uint8_t mode);

/**
 * @brief 设置HMC5883L磁偏角
 * @param declination 磁偏角(度)
 */
void HMC5883L_SetDeclination(float declination);

/**
 * @brief 获取HMC5883L磁偏角
 * @return 当前设置的磁偏角(度)
 */
float HMC5883L_GetDeclination(void);

/**
 * @brief 软重置HMC5883L
 * @return HMC5883L_OK: 重置成功, HMC5883L_ERROR: 重置失败
 */
uint8_t HMC5883L_Reset(void);

/**
 * @brief 数据就绪(DRDY)中断处理函数
 */
void HMC5883L_DRDY_Handler(void);

/**
 * @brief 判断HMC5883L是否数据就绪
 * @return true: 数据就绪, false: 数据未就绪
 */
bool HMC5883L_IsDataReady(void);

/**
 * @brief 设置HMC5883L采样率
 * @param dataRate 采样率设置值(HMC5883L_DATARATE_*)
 * @return HMC5883L_OK: 设置成功, HMC5883L_ERROR: 设置失败
 */
uint8_t HMC5883L_SetDataRate(uint8_t dataRate);

/**
 * @brief 设置HMC5883L增益
 * @param gain 增益设置值(HMC5883L_GAIN_*)
 * @return HMC5883L_OK: 设置成功, HMC5883L_ERROR: 设置失败
 */
uint8_t HMC5883L_SetGain(uint8_t gain);

/**
 * @brief 获取HMC5883L器件ID
 * @param id 存储ID的指针(3字节)
 * @return HMC5883L_OK: 获取成功, HMC5883L_ERROR: 获取失败
 */
uint8_t HMC5883L_GetID(uint8_t *id);

/**
 * @brief 计算磁航向角
 * @param x X轴磁场值
 * @param y Y轴磁场值
 * @return 磁航向角(度,0-360)
 */
float HMC5883L_CalculateHeading(float x, float y);

/**
 * @brief 读取原始数据并转换为磁场强度
 * @param data 数据结构体指针(用于存储转换后的数据)
 * @return HMC5883L_OK: 转换成功, HMC5883L_ERROR: 转换失败
 */
uint8_t HMC5883L_ReadRawData(HMC5883L_Data_t *data);

#endif /* HMC5883L_H */
